#include "Qt3DPicker.h"

#include "OsgUtil.h"

#include <gp_Ax1.hxx>

#include "VerticalAxisTransformHandler.h"
#include "CmdManager.h"
#include "Scene.h"
#include "SendPointHandlerBase.h"
#include "SelectHandler3D.h"
#include "OSGNodeMask.h"
#include "Operation/OpAdd.h"
#include "Operation/OpReplace.h"
#include "Ent.h"
#include "Pline2D.h"
#include "EntFromEdge.h"

VerticalAxisTransformHandler::VerticalAxisTransformHandler()
{
}

VerticalAxisTransformHandler::~VerticalAxisTransformHandler()
{
}

bool getStartDir(const  std::shared_ptr<Ent>& ent, osg::Vec3d& startPt, osg::Vec3d& startDir);

std::vector<TopoDS_Edge> convertEdge(const std::shared_ptr<Ent>& ent);

void VerticalAxisTransformHandler::input(const QVariant& data, const QString& rawInput, CommandSource cs)
{
	auto scene = getScene();
	auto sph = getSendPointHandler();
	auto selector = qobject_cast<SelectHandler3D*>(getSelectHandler());
	if (data.type() == QVariant::Bool)
	{
		bool esc = !data.toBool();
		if (esc)
		{
			selector->clearSelection();
			clearInput();
			emit finished();
			return;
		}
	}

	if (status() == 0)
	{
		if (selector)
		{
			selector->clearSelection();
			selector->beginSelect(D2LineMask | D2CurveMask);
			prompt(1, tr("选择二维轮廓线:"));
		}
		else
		{
			emit finished();
		}
		return;
	}


	if (status() == 1)
	{
		if (selector->done())
		{
			std::set<std::shared_ptr<INode>> selections = selector->selectionSet();
			if (selections.empty())
			{
				selector->beginSelect(D2LineMask | D2CurveMask);
				prompt(1, tr("选择二维轮廓线:"));
				return;
			}
			for (auto selection : selections)
			{
				auto ent = std::static_pointer_cast<Ent2D>(selection);
				auto parent = ent->getParent();
				UCS* ucs = dynamic_cast<UCS*>(parent);
				if (ucs && !m_ucs)
				{
					m_ucs = ucs;
				}
				if(ucs != m_ucs)
				{
					remark(tr("请选择同一平面内的图形"));
					emit finished();
					return;
				}
				if (ent->metaObject() == &Pline2D::staticMetaObject)
				{
					auto pline = std::static_pointer_cast<Pline2D>(ent);
					std::vector<std::shared_ptr<Ent>> explodeEnts;
					bool success = pline->explode(explodeEnts);
					if (success)
					{
						for (auto explodeEnt : explodeEnts)
						{
							auto ent2d = std::static_pointer_cast<Ent2D>(explodeEnt);
							m_ent2ds.push_back(ent2d);
						}
					}
				}
				else
				{
					m_ent2ds.push_back(ent);
				}
			}
			selector->clearSelection();
			selector->beginSelect(D2LineMask | D2CurveMask | D3LineMask | D3CurveMask, 1);
			prompt(2, tr("选择垂直轴:"));
		}		
		return;
	}

	if (status() == 2)
	{
		if (selector->done())
		{
			std::set<std::shared_ptr<INode>> selections = selector->selectionSet();
			if (selections.empty())
			{
				selector->beginSelect(D2LineMask | D2CurveMask | D3LineMask | D3CurveMask, 1);
				prompt(2, tr("选择垂直轴:"));
				return;
			}
			m_ent3D = std::static_pointer_cast<Ent>(*selections.begin());
			if (sph)
			{
				sph->setPointMask(CS_LBTNDOWN | CS_MOUSEMOVE);
			}
			enableMouseHandler(MouseHandlerID::PointSender);
			prompt(3, tr("指定基点:"));
		}
		return;
	}
	if (status() == 3)
	{
		if (data.type() == QVariant::Vector3D)
		{
			if (cs == CS_MOUSEMOVE)
				return;
			auto pt = data.value<QVector3D>();
			osg::Vec3d basePt = { pt.x(), pt.y(), pt.z() };
			auto spineEdges = makeEdges(m_ent3D);

			std::set<std::shared_ptr<INode>> result;
			selector->clearSelection();
			osg::Vec3d startPt, startDir;
			bool success = getStartDir(m_ent3D, startPt, startDir);
			if (!success)
			{
				remark(tr("获取三维图形起始点和起始方向失败"));
				emit finished();
				return;
			}
			osg::Vec3d dir = startDir;
			auto zAxis = m_ucs->zAxis();
			osg::Matrixd matrix;
			if ((osg::Vec3d(dir) * zAxis) > 0.99999847691328769880290124792571/*cos(0.1deg)*/)
			{
				auto trans = startPt - basePt;
				matrix.setTrans(trans);
			}
			else
			{
				osg::Matrixd t1, t2, t3, rot;
				t1.makeTranslate(-basePt);
				t2.makeTranslate(basePt);
				auto trans = startPt - basePt;
				t3.makeTranslate(trans);

				auto rotateAxisVec = zAxis ^ dir;
				rotateAxisVec.normalize();
				gp_Ax1 fromAx1(gp_Pnt(), gp_Dir(zAxis.x(), zAxis.y(), zAxis.z()));
				gp_Ax1 toAx1(gp_Pnt(), gp_Dir(dir.x(), dir.y(), dir.z()));
				double angle = fromAx1.Angle(toAx1);
				if (angle > M_PI)
					rotateAxisVec = -rotateAxisVec;
				rot.makeRotate(angle, rotateAxisVec);
				matrix = (t1 * rot * t2) * t3;
			}
			for (auto ent2d : m_ent2ds)
			{
				auto ent3d = makeEnt3DFromEnt2D(ent2d, scene, matrix);
				std::shared_ptr<Ent3DCurve> ent3dCurve = std::static_pointer_cast<Ent3DCurve>(ent3d);
				ent3dCurve->setColor(getCurrentColor());
				result.insert(ent3dCurve);
			}
			auto undoStack = scene->undoStack();
			undoStack->push(new OpAdd(result));
			emit finished();
		}
	}
	return;
}
